// Modules
mod actions;
mod appsettings;
mod imp;

// Imports
use crate::{
    config, dialogs, FileType, RnApp, RnMainHeader,
    RnSidebar,
};
use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext;
use gtk4::{gdk, gio, glib, Application, IconTheme};
use mytool_compose::Color;
use std::path::Path;
use tracing::{error, warn};

glib::wrapper! {
    pub(crate) struct RnAppWindow(ObjectSubclass<imp::RnAppWindow>)
        @extends gtk4::Widget, gtk4::Window, adw::Window, gtk4::ApplicationWindow, adw::ApplicationWindow,
        @implements gio::ActionGroup, gio::ActionMap, gtk4::Accessible, gtk4::Buildable,
                    gtk4::ConstraintTarget, gtk4::Native, gtk4::Root, gtk4::ShortcutManager;
}

impl RnAppWindow {
    const AUTOSAVE_INTERVAL_DEFAULT: u32 = 30;
    const PERIODIC_CONFIGSAVE_INTERVAL: u32 = 10;

    pub(crate) fn new(app: &Application) -> Self {
        glib::Object::builder().property("application", app).build()
    }

    #[allow(unused)]
    pub(crate) fn save_in_progress(&self) -> bool {
        self.property::<bool>("save-in-progress")
    }

    #[allow(unused)]
    pub(crate) fn set_save_in_progress(&self, save_in_progress: bool) {
        self.set_property("save-in-progress", save_in_progress.to_value());
    }

    #[allow(unused)]
    pub(crate) fn autosave(&self) -> bool {
        self.property::<bool>("autosave")
    }

    #[allow(unused)]
    pub(crate) fn set_autosave(&self, autosave: bool) {
        self.set_property("autosave", autosave.to_value());
    }

    #[allow(unused)]
    pub(crate) fn autosave_interval_secs(&self) -> u32 {
        self.property::<u32>("autosave-interval-secs")
    }

    #[allow(unused)]
    pub(crate) fn set_autosave_interval_secs(&self, autosave_interval_secs: u32) {
        self.set_property("autosave-interval-secs", autosave_interval_secs.to_value());
    }

    #[allow(unused)]
    pub(crate) fn righthanded(&self) -> bool {
        self.property::<bool>("righthanded")
    }

    #[allow(unused)]
    pub(crate) fn set_righthanded(&self, righthanded: bool) {
        self.set_property("righthanded", righthanded.to_value());
    }

    #[allow(unused)]
    pub(crate) fn touch_drawing(&self) -> bool {
        self.property::<bool>("touch-drawing")
    }

    #[allow(unused)]
    pub(crate) fn set_touch_drawing(&self, touch_drawing: bool) {
        self.set_property("touch-drawing", touch_drawing.to_value());
    }

    #[allow(unused)]
    pub(crate) fn focus_mode(&self) -> bool {
        self.property::<bool>("focus-mode")
    }

    #[allow(unused)]
    pub(crate) fn set_focus_mode(&self, focus_mode: bool) {
        self.set_property("focus-mode", focus_mode.to_value());
    }

    #[allow(unused)]
    pub(crate) fn respect_borders(&self) -> bool {
        self.property::<bool>("respect-borders")
    }

    pub(crate) fn app(&self) -> RnApp {
        self.application().unwrap().downcast::<RnApp>().unwrap()
    }

    pub(crate) fn overview(&self) -> adw::TabOverview {
        self.imp().overview.get()
    }

    pub(crate) fn main_header(&self) -> RnMainHeader {
        self.imp().main_header.get()
    }

    pub(crate) fn split_view(&self) -> adw::OverlaySplitView {
        self.imp().split_view.get()
    }

    pub(crate) fn sidebar(&self) -> RnSidebar {
        self.imp().sidebar.get()
    }

    /// Must be called after application is associated with the window else the init will panic
    pub(crate) fn init(&self) {
        let imp = self.imp();

        imp.sidebar.get().init(self);
        imp.main_header.get().init(self);

        // An initial tab. Must! come before setting up the settings binds and import
        // self.add_initial_tab();

        // actions and settings AFTER widget inits
        self.setup_icon_theme();
        self.setup_actions();
        self.setup_action_accels();

        if !self.app().settings_schema_found() {
            // Display an error toast if settings schema could not be found
            // self.overlays().dispatch_toast_error(&gettext(
            //     "Settings schema is not installed. App settings could not be loaded and won't be saved.",
            // ));
        } else {
            if let Err(e) = self.setup_settings_binds() {
                error!("Failed to setup settings binds, Err: {e:?}");
            }
            if let Err(e) = self.setup_periodic_save() {
                error!("Failed to setup periodic save, Err: {e:?}");
            }
            if let Err(e) = self.load_settings() {
                error!("Failed to load initial settings, Err: {e:?}");
            }
        }

        // Anything that needs to be done right before showing the appwindow

        // Set undo / redo as not sensitive as default - setting it in .ui file did not work for some reason

        // if let Some(wrapper) = self.active_tab_wrapper() {
        // self.refresh_ui_from_engine(&wrapper);
        // }
    }

    fn setup_icon_theme(&self) {
        // add icon theme resource path because automatic lookup does not work in the devel build.
        let app_icon_theme =
            IconTheme::for_display(&<Self as gtk4::prelude::WidgetExt>::display(self));
        app_icon_theme.add_resource_path((String::from(config::APP_IDPATH) + "icons").as_str());
    }

    /// Called to close the window
    pub(crate) fn close_force(&self) {
        if self.app().settings_schema_found() {
            // Saving all state
            if let Err(e) = self.save_to_settings() {
                error!("Failed to save appwindow to settings, Err: {e:?}");
            }
        }

        // Closing the state tasks channel receiver for all tabs
        // for tab in self
        //     .tabs_snapshot()
        //     .into_iter()
        //     .map(|p| p.child().downcast::<RnCanvasWrapper>().unwrap())
        // {
        //     let _ = tab.canvas().engine_mut().set_active(false);
        //     tab.canvas()
        //         .engine_ref()
        //         .engine_tasks_tx()
        //         .send(EngineTask::Quit);
        // }

        self.destroy();
    }
}
